package com.internetCafes.spms.web.customer.bizservice.impl.customer;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.internetCafes.spms.common.utils.ExcelImportUtil;
import com.internetCafes.spms.common.utils.ShiroUtils;
import com.internetCafes.spms.common.utils.entity.page.PageItemDTO;
import com.internetCafes.spms.common.utils.entity.page.PageItemUtil;
import com.internetCafes.spms.common.utils.entity.page.PageItemVO;
import com.internetCafes.spms.core.exception.RRException;
import com.internetCafes.spms.core.exception.RRExceptionCodeEnum;
import com.internetCafes.spms.core.utils.FileUtils;
import com.internetCafes.spms.core.utils.IdWorker;
import com.internetCafes.spms.web.common.model.DataMarkBaseReq;
import com.internetCafes.spms.web.customer.bizservice.customer.IEntCustomerBizService;
import com.internetCafes.spms.web.customer.common.component.msg.impl.MsgComponent;
import com.internetCafes.spms.web.customer.common.cont.CommonConst;
import com.internetCafes.spms.web.customer.common.cont.CustomerConst;
import com.internetCafes.spms.web.customer.common.cont.UserConst;
import com.internetCafes.spms.web.customer.common.handler.TransferUserTreeHandler;
import com.internetCafes.spms.web.customer.common.mode.CustomerMode;
import com.internetCafes.spms.web.customer.common.util.UserInfoUtil;
import com.internetCafes.spms.web.customer.common.util.quali.CustomerQualiUtil;
import com.internetCafes.spms.web.customer.entity.area.Area;
import com.internetCafes.spms.web.customer.entity.customer.*;
import com.internetCafes.spms.web.customer.entity.role.RoleDeptDataAsso;
import com.internetCafes.spms.web.customer.entity.user.EntUserInfo;
import com.internetCafes.spms.web.customer.model.ExcelImportResultRes;
import com.internetCafes.spms.web.customer.model.FileUploadRes;
import com.internetCafes.spms.web.customer.model.area.EntAreaSaleDo;
import com.internetCafes.spms.web.customer.model.area.EntAreaSalePo;
import com.internetCafes.spms.web.customer.model.customer.*;
import com.internetCafes.spms.web.customer.model.customer.cooperation.CustomerCooperationDo;
import com.internetCafes.spms.web.customer.model.customer.cooperation.CustomerCooperationPo;
import com.internetCafes.spms.web.customer.model.customer.cooperation.CustomerCooperationSaveReq;
import com.internetCafes.spms.web.customer.model.customer.quali.CustomerQualiDo;
import com.internetCafes.spms.web.customer.model.customer.quali.CustomerQualiPo;
import com.internetCafes.spms.web.customer.model.customer.quali.QualiMatchReq;
import com.internetCafes.spms.web.customer.model.customer.quali.QualiMatchRes;
import com.internetCafes.spms.web.customer.model.role.RoleDeptDataDo;
import com.internetCafes.spms.web.customer.model.role.RoleDeptDataPo;
import com.internetCafes.spms.web.customer.model.user.EntUserEmployeeInfoListDo;
import com.internetCafes.spms.web.customer.model.user.EntUserEmployeeInfoListPo;
import com.internetCafes.spms.web.customer.model.user.UserDo;
import com.internetCafes.spms.web.customer.model.user.UserPo;
import com.internetCafes.spms.web.customer.service.area.IAreaSaleService;
import com.internetCafes.spms.web.customer.service.area.IAreaService;
import com.internetCafes.spms.web.customer.service.customer.*;
import com.internetCafes.spms.web.customer.service.role.IRoleDeptDataAssoService;
import com.internetCafes.spms.web.customer.service.user.IEntUserInfoService;
import com.internetCafes.spms.web.sys.model.UserInfo;
import com.internetCafes.spms.web.tenant.model.TenantInfo;
import com.internetCafes.spms.web.tenant.model.podo.TenantDeptInfoPlusDo;
import com.internetCafes.spms.web.tenant.model.podo.TenantDeptInfoPlusPo;
import com.internetCafes.spms.web.tenant.service.ITenantDeptInfoPlusService;
import com.internetCafes.spms.web.tenant.service.TenantDeptInfoService;
import com.internetCafes.spms.web.tenant.service.TenantInfoService;
import com.internetCafes.spms.web.toolbox.cont.QualiConst;
import com.internetCafes.spms.web.toolbox.entity.QualiConf;
import com.internetCafes.spms.web.toolbox.service.IQualiConfService;
import com.sms.common.util.hutool.core.bean.BeanUtil;
import com.sms.common.util.hutool.core.collection.CollectionUtil;
import com.sms.common.util.hutool.core.date.DatePattern;
import com.sms.common.util.hutool.core.date.DateUtil;
import com.sms.common.util.hutool.core.util.ObjectUtil;
import com.sms.common.util.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.jeecgframework.poi.excel.entity.ImportSheetParams;
import org.nlpcn.commons.lang.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.multipart.MultipartFile;

import javax.validation.constraints.NotEmpty;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.Duration;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Service
public class EntCustomerBizServiceImpl implements IEntCustomerBizService {

    @Autowired
    private ICustomerFlowService flowService;
    @Autowired
    private ICustomerService customerService;
    @Autowired
    private ICustomerQualiImageService qualiImageService;
    @Autowired
    private IEntUserInfoService userInfoService;
    @Autowired
    private IQualiConfService qualiConfService;
    @Autowired
    private ICustomerFollowService followService;
    @Autowired
    private TenantDeptInfoService deptInfoService;
    @Autowired
    private IAreaService areaService;
    @Autowired
    private MsgComponent msgComponent;
    @Autowired
    private ICustomerCooperationService cooperationService;
    @Autowired
    private TenantInfoService tenantInfoService;
    @Autowired
    private ITenantDeptInfoPlusService deptInfoPlusService;
    @Autowired
    private IRoleDeptDataAssoService roleDeptDataAssoService;
    @Autowired
    private IAreaSaleService areaSaleService;


    @Value("${system.upload.others}")
    private String othersPath;

    @Value("${system.upload.pic}")
    private String picPath;

    @Value("${system.remote.url}")
    private String remoteUrl;

    /**
     * 企业导出头
     */
    private final List<String> ENT_EXPORT_TITLE = Lists.newArrayList("序号", "企业名称", "地市", "地区", "详细地址", "联系人", "职务", "联系电话", "销售", "去年是否成交", "今年是否成交", "重要情况备注");

    /**
     * 个人客户导出头
     */
    private final List<String> PERSON_EXPORT_TITLE = Lists.newArrayList("序号", "姓名", "地市", "地区", "邮寄地址", "联系人电话", "微信号", "身份证号", "来源途径", "来源途径备注");


    /**
     * 个人客户导入表头
     */
    private final String[] PERSON_EXCEL_HEADER = new String[]{"姓名", "联系人手机号码", "微信号", "身份证号", "邮寄地址", "所在地区（市）", "所在区域（区/县）", "来源途径", "来源途径说明"};

    /**
     * 企业客户表头
     */
    private final String[] ENT_EXCEL_HEADER = new String[]{"企业名称", "所在地区（市）", "所在区域（区/县）", "社会统一信用代码", "资质项", "联系人", "职务", "联系人手机号码", "微信号", "法人代表", "法人手机号", "企业地址", "备注"};

    @Override
    public Boolean mark(DataMarkBaseReq req) {
        if (CollectionUtil.isEmpty(req.getIdList())
                || !CustomerConst.MarkType.getTypeIdList().contains(req.getTypeId())
                || ObjectUtil.isNull(req.getFlag())) {
            throw new RRException(RRExceptionCodeEnum.PARAM_ERROR);
        }
        LambdaUpdateWrapper<Customer> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.in(Customer::getId, req.getIdList());
        if (CustomerConst.MarkType.UN_NECESSARY.getId().equals(req.getTypeId())) {
            updateWrapper.set(Customer::getUnNecessaryFlag, (req.getFlag() ? CommonConst.FlagEnum.IS.getId() : CommonConst.FlagEnum.NOT.getId()));
        }
        return customerService.update(updateWrapper);
    }

    @Override
    public Workbook createCustomerExcel(CustomerExcelReq req) {
        CustomerPagingReq customerPagingReq = new CustomerPagingReq();
        BeanUtil.copyProperties(req, customerPagingReq);
        // 非区域名单的时候，销售只展示自己的客户
        CustomerPagingDo customerPagingDo = customerPagingFilter(customerPagingReq);
        List<CustomerPagingPo> listPo = customerService.customerPoList(customerPagingDo);

        int cooperationAmount = 0;

        Map<Long, List<CustomerCooperation>> cooperationGroupByCustomerId = new HashMap<>();
        // 获取合作记录
        if (CustomerConst.TypeEnum.DEAL.getId().equals(req.getTypeId())) {
            if (CollectionUtil.isNotEmpty(listPo)) {
                List<Long> customerId = listPo.stream()
                        .map(CustomerPagingPo::getId)
                        .collect(Collectors.toList());

                cooperationGroupByCustomerId = cooperationService.list(new LambdaQueryWrapper<CustomerCooperation>()
                                .in(CustomerCooperation::getCustomerId, customerId))
                        .stream()
                        .sorted(Comparator.comparing(CustomerCooperation::getIncomeDate).reversed())
                        .collect(Collectors.groupingBy(CustomerCooperation::getCustomerId));

                if (CollectionUtil.isNotEmpty(cooperationGroupByCustomerId)) {
                    List<Map.Entry<Long, List<CustomerCooperation>>> customerCooperationList
                            = new ArrayList(cooperationGroupByCustomerId.entrySet());

                    CollectionUtil.sort(customerCooperationList, (cooperationList1, cooperationList2) -> (cooperationList2.getValue().size() - cooperationList1.getValue().size()));
                    cooperationAmount = CollectionUtil.getFirst(customerCooperationList).getValue().size();
                }

            }
        }

        if (CommonConst.FlagEnum.IS.getId().equals(req.getEnterpriseFlag())) {
            List<String> title = new ArrayList<>(ENT_EXPORT_TITLE);
            for (int i = 0; cooperationAmount > i; i++) {
                title.add("成交记录");
            }
            return createEntWorkbook(title, listPo, cooperationGroupByCustomerId);
        }
        List<String> title = new ArrayList<>(PERSON_EXPORT_TITLE);
        for (int i = 0; cooperationAmount > i; i++) {
            title.add("成交记录");
        }
        return createPersonWorkbook(title, listPo, cooperationGroupByCustomerId);
    }

    /**
     * 创建个人客户导出列表
     *
     * @param title                        表格抬头
     * @param listPo                       数据列表
     * @param cooperationGroupByCustomerId 成交记录分组
     * @return workbook
     */
    private Workbook createPersonWorkbook(List<String> title, List<CustomerPagingPo> listPo, Map<Long, List<CustomerCooperation>> cooperationGroupByCustomerId) {
        HSSFWorkbook workbook = new HSSFWorkbook();

        HSSFCellStyle cellStyle = workbook.createCellStyle();
        cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        // 创建表头
        HSSFSheet sheet = workbook.createSheet("个人客户表");

        int rowIndex = 1;
        Row row = sheet.createRow(rowIndex++);
        Cell cell;
        // 表头
        for (int i = 0; i < title.size(); i++) {
            cell = row.createCell(i);
            cell.setCellValue(title.get(i));
        }

        // 填写数据
        for (CustomerPagingPo po : listPo) {
            row = sheet.createRow(rowIndex);
            cell = row.createCell(0);
            cell.setCellValue(rowIndex - 1);
            cell = row.createCell(1);
            cell.setCellValue(po.getName());
            cell = row.createCell(2);
            cell.setCellValue(po.getCityName());
            cell = row.createCell(3);
            cell.setCellValue(po.getAreaName());
            cell = row.createCell(4);
            cell.setCellValue(po.getMailingAddress());
            cell = row.createCell(5);
            cell.setCellValue(po.getContactsMobile());
            cell = row.createCell(6);
            cell.setCellValue(po.getContactsWechat());
            cell = row.createCell(7);
            cell.setCellValue(po.getContactsIdCard());
            cell = row.createCell(8);
            cell.setCellValue(CustomerConst.OriginTag.getTagById(po.getOriginTag()));
            cell = row.createCell(9);
            cell.setCellValue(po.getOriginRemark());

            if (cooperationGroupByCustomerId.containsKey(po.getId())) {
                List<CustomerCooperation> cooperations = cooperationGroupByCustomerId.get(po.getId());
                for (int i = 0; i < cooperations.size(); i++) {
                    CustomerCooperation customerCooperation = cooperations.get(i);
                    String value = "";
                    if (ObjectUtil.isNotNull(customerCooperation.getIncomeDate())) {
                        String date = DateUtil.format(customerCooperation.getIncomeDate(), DatePattern.NORM_DATE_PATTERN);
                        value = date + "(" + (ObjectUtil.isNotNull(customerCooperation.getIncome()) ? customerCooperation.getIncome() : BigDecimal.ZERO) + ")";
                    }

                    cell = row.createCell(10 + i);
                    cell.setCellValue(value);
                }
            }
            rowIndex++;
        }
        for (int i = 0; i < title.size(); i++) {
            sheet.autoSizeColumn(i);
        }
        // 标题
        row = sheet.createRow(0);
        row.setHeight((short) 500);
        /*Cell cell = row.createCell(0);
        cell.setCellValue("客户表");*/
        cell = row.createCell(4);
        cell.setCellValue("历年客户清单");
        cell.setCellStyle(cellStyle);
        // 前两格合并
        sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 3));
        sheet.addMergedRegion(new CellRangeAddress(0, 0, 4, PERSON_EXPORT_TITLE.size() - 1));

        if (title.size() > PERSON_EXPORT_TITLE.size()) {
            cell = row.createCell(PERSON_EXPORT_TITLE.size());
            cell.setCellValue("成交记录");
            cell.setCellStyle(cellStyle);
            CellRangeAddress cellRangeAddress = new CellRangeAddress(0, 0, PERSON_EXPORT_TITLE.size(), title.size() - 1);
            if (cellRangeAddress.getNumberOfCells() >= 2) {
                sheet.addMergedRegion(new CellRangeAddress(0, 0, PERSON_EXPORT_TITLE.size(), title.size() - 1));
            }
        }

        sheet.createFreezePane(4, 2);
        return workbook;
    }

    /**
     * 创建企业客户导出列表
     *
     * @param title                        表格抬头
     * @param listPo                       数据列表
     * @param cooperationGroupByCustomerId 成交记录分组
     * @return workbook
     */
    private Workbook createEntWorkbook(List<String> title, List<CustomerPagingPo> listPo, Map<Long, List<CustomerCooperation>> cooperationGroupByCustomerId) {
        HSSFWorkbook workbook = new HSSFWorkbook();

        HSSFCellStyle cellStyle = workbook.createCellStyle();
        cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        // 创建表头
        HSSFSheet sheet = workbook.createSheet("企业客户表");


        int rowIndex = 1;
        Row row = sheet.createRow(rowIndex++);
        Cell cell;
        // 表头
        for (int i = 0; i < title.size(); i++) {
            cell = row.createCell(i);
            cell.setCellValue(title.get(i));
        }

        // 填写数据
        for (CustomerPagingPo po : listPo) {
            row = sheet.createRow(rowIndex);
            cell = row.createCell(0);
            cell.setCellValue(rowIndex - 1);
            cell = row.createCell(1);
            cell.setCellValue(po.getName());
            cell = row.createCell(2);
            cell.setCellValue(po.getCityName());
            cell = row.createCell(3);
            cell.setCellValue(po.getAreaName());
            cell = row.createCell(4);
            cell.setCellValue(po.getAddressDetail());
            cell = row.createCell(5);
            cell.setCellValue(po.getContactsName());
            cell = row.createCell(6);
            cell.setCellValue(po.getContactsPosition());
            cell = row.createCell(7);
            cell.setCellValue(po.getContactsMobile());
            cell = row.createCell(8);
            cell.setCellValue(po.getFollowUserName());
            cell = row.createCell(9);
            cell.setCellValue(CommonConst.FlagEnum.getFlagById(po.getLastYearDealFlag()));
            cell = row.createCell(10);
            cell.setCellValue(CommonConst.FlagEnum.getFlagById(po.getThisYearDealFlag()));
            cell = row.createCell(11);
            cell.setCellValue(po.getRemark());
            if (cooperationGroupByCustomerId.containsKey(po.getId())) {
                List<CustomerCooperation> cooperations = cooperationGroupByCustomerId.get(po.getId());
                for (int i = 0; i < cooperations.size(); i++) {
                    CustomerCooperation customerCooperation = cooperations.get(i);
                    String value = "";
                    if (ObjectUtil.isNotNull(customerCooperation.getIncomeDate())) {
                        String date = DateUtil.format(customerCooperation.getIncomeDate(), DatePattern.NORM_DATE_PATTERN);
                        value = date + "(" + (ObjectUtil.isNotNull(customerCooperation.getIncome()) ? customerCooperation.getIncome() : BigDecimal.ZERO) + ")";
                    }

                    cell = row.createCell(12 + i);
                    cell.setCellValue(value);
                }
            }
            rowIndex++;
        }
        for (int i = 0; i < title.size(); i++) {
            sheet.autoSizeColumn(i);
        }
        // 标题
        row = sheet.createRow(0);
        row.setHeight((short) 500);
        /*Cell cell = row.createCell(0);
        cell.setCellValue("客户表");*/
        cell = row.createCell(4);
        cell.setCellValue("历年客户清单");
        cell.setCellStyle(cellStyle);
        // 前两格合并
        sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 3));
        sheet.addMergedRegion(new CellRangeAddress(0, 0, 4, ENT_EXPORT_TITLE.size() - 1));

        if (title.size() > ENT_EXPORT_TITLE.size()) {
            cell = row.createCell(ENT_EXPORT_TITLE.size());
            cell.setCellValue("成交记录");
            cell.setCellStyle(cellStyle);
            CellRangeAddress cellRangeAddress = new CellRangeAddress(0, 0, ENT_EXPORT_TITLE.size(), title.size() - 1);
            if (cellRangeAddress.getNumberOfCells() >= 2) {
                sheet.addMergedRegion(new CellRangeAddress(0, 0, ENT_EXPORT_TITLE.size(), title.size() - 1));
            }
        }

        sheet.createFreezePane(4, 2);
        return workbook;
    }


    @Override
    public boolean infoConfirm(CustomerInfoConfirmReq req) {
        // 信用代码验证
        if (StrUtil.isNotBlank(req.getCertificateCode())) {
            LambdaQueryWrapper<Customer> qw = new LambdaQueryWrapper<Customer>()
                    .eq(Customer::getCertificateCode, req.getCertificateCode())
                    .eq(Customer::getDelFlag, CommonConst.FlagEnum.NOT.getId());
            if (ObjectUtil.isNotNull(req.getId())) {
                qw.ne(Customer::getId, req.getId());
            }
            List<CustomerDetailPo> customerList = customerService.customerPoDetailList(new CustomerDetailListDo().setCertificateCode(req.getCertificateCode()));
            if (!CollectionUtil.isEmpty(customerList)) {
                CustomerDetailPo customerInfo = CollectionUtil.getFirst(customerList);
                String name = StrUtil.isBlank(customerInfo.getFollowUserName()) ? "" : "【" + customerInfo.getFollowUserName() + "】的";
                if (CustomerConst.TypeEnum.DEAL.getId().equals(customerInfo.getTypeId())) {
                    throw new RRException("该客户已经是" + name + "成交客户，不能进行添加");
                }
                if (CustomerConst.TypeEnum.INTENTION.getId().equals(customerInfo.getTypeId())) {
                    throw new RRException("该客户已经是" + name + "意向客户，是否添加合作记录？");
                }
                if (CustomerConst.TypeEnum.GENERAL.getId().equals(customerInfo.getTypeId())) {
                    List<UserPo> saleList = userInfoService.userPoList(new UserDo().setSaleAreaIdList(Collections.singletonList(customerInfo.getAreaId())));
                    if (CollectionUtil.isNotEmpty(saleList)) {
                        name = "【" + (
                                saleList.stream().map(UserPo::getNickName).collect(Collectors.joining(", "))
                        ) + "】的";
                    } else {
                        name = "";
                    }
                    throw new RRException("该客户已在" + name + "区域名单中，是否添加合作记录？", 600, customerInfo.getId());
                }
                throw new RRException(RRExceptionCodeEnum.CUSTOMER_CODE_REPEAT);
            }
        }
        // 客户名称验证
        if (StrUtil.isNotBlank(req.getName())) {
            LambdaQueryWrapper<Customer> qw = new LambdaQueryWrapper<Customer>()
                    .eq(Customer::getName, req.getName())
                    .eq(Customer::getDelFlag, CommonConst.FlagEnum.NOT.getId());
            if (ObjectUtil.isNotNull(req.getId())) {
                qw.ne(Customer::getId, req.getId());
            }
            List<Customer> customerList = customerService.list(qw);
            if (CollectionUtil.isNotEmpty(customerList)) {
                Long followUserId = CollectionUtil.getFirst(customerList).getFollowUserId();
                List<UserPo> userListPo = userInfoService.userPoList(new UserDo().setIdList(Collections.singletonList(followUserId)));
                if (CollectionUtil.isNotEmpty(userListPo)) {
                    UserPo userPo = CollectionUtil.getFirst(userListPo);
                    throw new RRException("该客户名称已在" + userPo.getDeptName() + "的" + userPo.getNickName() + "下存在");
                }
            }
        }
        return true;
    }

    @Override
    public ExcelImportResultRes batchSave(CustomerBatchSaveReq req) {
        return CustomerMode.batchSave(req);
    }

    @Override
    public FileUploadRes fileUpload(MultipartFile file) {
        if (file.isEmpty()) {
            throw new RRException(RRExceptionCodeEnum.DATA_IS_NULL);
        }

        IdWorker id = new IdWorker(2);
        String fileName = id.nextId() + "";
        try {
            fileName = FileUtils.transform(file, picPath, fileName);
        } catch (Exception e) {
            throw new RRException(RRExceptionCodeEnum.FAIL_FILE_SAVE);
        }

        return new FileUploadRes(fileName, remoteUrl + "pic/");
    }

    @Override
    public List<CustomerPersonImportExcel> personExcelImport(MultipartFile file) {

        if (file.isEmpty()) {
            throw new RRException(RRExceptionCodeEnum.DATA_IS_NULL);
        }

        IdWorker id = new IdWorker(2);
        String fileType = Objects.requireNonNull(file.getOriginalFilename()).substring(file.getOriginalFilename().lastIndexOf("."));
        File videoFilePath = new File(othersPath);
        if (!videoFilePath.exists()) {
            videoFilePath.mkdirs();
        }

        if (fileType.toUpperCase().endsWith("XLS") || fileType.toUpperCase().endsWith("XLSX")) {
            String filePath = othersPath + File.separator + id.nextId() + fileType;

            try {
                file.transferTo(new File(filePath));
            } catch (IOException e) {
                e.printStackTrace();
            }

            Map<String, ImportSheetParams> sheetClassParamsMap = new HashMap<>();
            Map<String, Object> excel2Map;
            sheetClassParamsMap.put("Sheet1", new ImportSheetParams("personCustomer", 1, 1,
                    PERSON_EXCEL_HEADER,
                    CustomerPersonImportExcel.class));
            try {
                excel2Map = ExcelImportUtil.importExcelSheetFirst(new File(filePath), sheetClassParamsMap, null);
            } catch (Exception e) {
                throw new RRException(RRExceptionCodeEnum.DATA_IS_NULL);
            }
            return (List<CustomerPersonImportExcel>) excel2Map.get("Sheet1");

        } else {
            throw new RRException(RRExceptionCodeEnum.FILE_FORMAT_ERROR);
        }
    }

    @Override
    public List<CustomerEntImportExcel> entExcelImport(MultipartFile file) {
        if (file.isEmpty()) {
            throw new RRException(RRExceptionCodeEnum.DATA_IS_NULL);
        }

        IdWorker id = new IdWorker(2);
        String fileType = Objects.requireNonNull(file.getOriginalFilename()).substring(file.getOriginalFilename().lastIndexOf("."));
        File videoFilePath = new File(othersPath);
        if (!videoFilePath.exists()) {
            videoFilePath.mkdirs();
        }

        if (fileType.toUpperCase().endsWith("XLS") || fileType.toUpperCase().endsWith("XLSX")) {
            String filePath = othersPath + File.separator + id.nextId() + fileType;

            try {
                file.transferTo(new File(filePath));
            } catch (IOException e) {
                e.printStackTrace();
            }

            Map<String, ImportSheetParams> sheetClassParamsMap = new HashMap<>();
            Map<String, Object> excel2Map;
            sheetClassParamsMap.put("Sheet1", new ImportSheetParams("customerEntImportExcel", 1, 1,
                    ENT_EXCEL_HEADER,
                    CustomerEntImportExcel.class));
            try {
                excel2Map = ExcelImportUtil.importExcelSheetFirst(new File(filePath), sheetClassParamsMap, null);
            } catch (Exception e) {
                throw new RRException(RRExceptionCodeEnum.DATA_IS_NULL);
            }
            return (List<CustomerEntImportExcel>) excel2Map.get("Sheet1");
        } else {
            throw new RRException(RRExceptionCodeEnum.FILE_FORMAT_ERROR);
        }
    }

    @Override
    public List<CustomerPersonExcel> customerPersonExcel(CustomerExcelReq req) {
        CustomerPagingDo customerPagingDo = new CustomerPagingDo();
        BeanUtil.copyProperties(req, customerPagingDo);
        List<CustomerPagingPo> listPo = customerService.customerPoList(customerPagingDo);
        return listPo.stream().map(
                        po -> {
                            CustomerPersonExcel res = new CustomerPersonExcel();
                            BeanUtil.copyProperties(po, res);
                            res.setAreaDetail(StrUtil.join(po.getCityName(), po.getAreaName()));
                            return res;
                        })
                .collect(Collectors.toList());
    }

    @Override
    public List<CustomerEntExcel> customerEntExcel(CustomerExcelReq req) {
        CustomerPagingDo customerPagingDo = new CustomerPagingDo();
        BeanUtil.copyProperties(req, customerPagingDo);
        List<CustomerPagingPo> listPo = customerService.customerPoList(customerPagingDo);
        return listPo.stream().map(
                        po -> {
                            CustomerEntExcel res = new CustomerEntExcel();
                            BeanUtil.copyProperties(po, res);
                            res.setAreaDetail(StrUtil.join(po.getCityName(), po.getAreaName()));
                            return res;
                        })
                .collect(Collectors.toList());
    }

    @Override
    public List<QualiMatchRes> qualiMatchList(QualiMatchReq req) {

        List<QualiConf> qualiPoList = qualiConfService.list();
        return qualiPoList.stream()
                .map(qualiPo ->
                        new QualiMatchRes()
                                .setId(qualiPo.getId())
                                .setName(qualiPo.getQualiCode() +
                                        QualiConst.GradeType.getTypeByTag(qualiPo.getGradeTag())))
                .filter(qualiPo -> StrUtil.isNotBlank(req.getName()) && qualiPo.getName().contains(req.getName()))
                .collect(Collectors.toList());
    }

    @Override
    public List<CustomerTransferUserTreeRes> customerTransferUserTree(CustomerTransferUserTreeReq req) {

        /*
         * 一、筛选
         *      1-管理员 manager_flag null . 展示所有人列表
         *      2-地区管理员，展示对应部门数据人员
         * 二、转让规则
         *      管理层，能够进行转让
         *      销售，转让只支持向上管理层转让
         */

        // 部门列表
        List<CustomerTransferUserTreeRes> deptInfoPoList = deptInfoService.allList()
                .stream()
                .map(po -> new CustomerTransferUserTreeRes().setId(po.getId()).setDeptName(po.getDeptName()).setParentId(po.getParentId()))
                .collect(Collectors.toList());

        Long tenantId = ShiroUtils.getUserEntity().getDeptId();
        if (ObjectUtil.isNotNull(tenantId)) {
            TenantInfo tenantInfo = tenantInfoService.findById(tenantId);
            // 添加根节点部门，将根节点部门进行展示
            deptInfoPoList.add(new CustomerTransferUserTreeRes(0L, tenantInfo.getTenantName(), UserConst.DEPT_ROOT_PARENT));
        }

        // 获取人员数据
        List<CustomerTransferUserTreeRes.User> userEmployeeInfoPoList
                = userInfoService.userEmployeeInfoListPo(new EntUserEmployeeInfoListDo())
                .stream()
                .map(userPo -> {
                    CustomerTransferUserTreeRes.User userRes = new CustomerTransferUserTreeRes.User();
                    BeanUtil.copyProperties(userPo, userRes);
                    userRes.setName(userPo.getNickName());
                    return userRes;
                }).collect(Collectors.toList());

        // 管理员用户 获取全部列表
        UserInfo userEntity = ShiroUtils.getUserEntity();
        TransferUserTreeHandler userTreeHandler = TransferUserTreeHandler.getInstance();
        List<CustomerTransferUserTreeRes> result = userTreeHandler.customerTransferUserTree(req, deptInfoPoList, userEmployeeInfoPoList, userEntity);
        if (CustomerConst.TransferUserTreeAction.CUSTOMER_TRANSFER.getId().equals(req.getActionId()) ||
                UserInfoUtil.entSuperAdminJudge(userEntity)) {
            return result;
        }
        if (!UserInfoUtil.entSuperAdminJudge(userEntity)) {
            // 获取授权权限部门信息
            List<Long> roleDeptIdList = roleDeptDataAssoService.listPo(new RoleDeptDataDo().setUserId(userEntity.getId()))
                    .stream().map(RoleDeptDataPo::getDeptId)
                    .collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(roleDeptIdList)) {
                List<CustomerTransferUserTreeRes> totalDeptList = deptInfoPoList.stream()
                        .map(po -> new CustomerTransferUserTreeRes().setId(po.getId()).setDeptName(po.getDeptName()).setParentId(po.getParentId()))
                        .collect(Collectors.toList());

                List<CustomerTransferUserTreeRes> totalDeptTree = userTreeHandler.totalDeptTree(totalDeptList);

                Map<Long, List<CustomerTransferUserTreeRes.User>> userDataMapByDeptId = userEmployeeInfoPoList.stream()
                        .filter(userPo -> roleDeptIdList.contains(userPo.getDeptId()))
                        .collect(Collectors.groupingBy(CustomerTransferUserTreeRes.User::getDeptId));

                Map<Long, List<CustomerTransferUserTreeRes.User>> userMapByDeptId = userTreeHandler.deptTreeSplit(result)
                        .stream()
                        .collect(Collectors.toMap(CustomerTransferUserTreeRes::getId, CustomerTransferUserTreeRes::getUserList));

                userTreeHandler.deptUserAdd(totalDeptTree, userDataMapByDeptId, userMapByDeptId);
                userTreeHandler.clearNullUserNode(totalDeptTree);
                result = totalDeptTree;
            }
        }
        return result;
    }

    @Override
    public CustomerCountRes customerCount(Long customerId) {
        // 获取客户信息
        Customer customerPo = customerService.getById(customerId);

        if (ObjectUtil.isNull(customerPo)) {
            throw new RRException(RRExceptionCodeEnum.DATA_NOT_EXIST);
        }

        List<CustomerFollow> followList = followService.list(
                new LambdaQueryWrapper<CustomerFollow>()
                        .eq(CustomerFollow::getCustomerId, customerId)
                        .orderByDesc(CustomerFollow::getCreateTime));
        long unFollowDayAmount;
        Date nowTime = new Date();
        if (CollectionUtil.isNotEmpty(followList)) {
            unFollowDayAmount = Duration.between(nowTime.toInstant(), CollectionUtil.getFirst(followList).getCreateTime().toInstant()).toDays();
        } else {
            unFollowDayAmount = Duration.between(nowTime.toInstant(), customerPo.getCreateTime().toInstant()).toDays();
        }
        unFollowDayAmount = Math.abs(unFollowDayAmount);
        return new CustomerCountRes().setUnFollowDayAmount(++unFollowDayAmount);
    }

    @Override
    public List<QualiMatchRes> qualiMatch(QualiMatchReq req) {

        // 提供默认值 无
        if (StrUtil.isBlank(req.getQualisContent())) {
            req.setQualisContent(CustomerConst.QUALI_CONTENT_NULL);
        }

        List<QualiConf> qualiPoList = qualiConfService.list();

        Map<String, QualiMatchRes> qualiMatchMap = qualiPoList.stream()
                .map(qualiPo -> {
                    QualiMatchRes res = new QualiMatchRes();
                    BeanUtil.copyProperties(qualiPo, res);
                    res.setName(qualiPo.getQualiCode(), qualiPo.getGradeTag());
                    return res;
                })
                .collect(Collectors.toMap(QualiMatchRes::getName, Function.identity()));

        // 智能匹配
        List<QualiMatchRes> qualiMatchRes = CustomerQualiUtil.qualiContentMatch(qualiMatchMap, req.getQualisContent());

        // 列表匹配
        List<QualiMatchRes> qualiMatchListRes = qualiPoList.stream()
                .map(qualiPo -> {
                    QualiMatchRes res = new QualiMatchRes();
                    BeanUtil.copyProperties(qualiPo, res);
                    res.setName(qualiPo.getQualiCode(), qualiPo.getGradeTag());
                    return res;
                })
                .filter(qualiPo -> StrUtil.isNotBlank(req.getQualisContent()) && qualiPo.getName().contains(req.getQualisContent()))
                .collect(Collectors.toList());

        qualiMatchRes.addAll(qualiMatchListRes);

        return qualiMatchRes.stream()
                .distinct()
                .collect(Collectors.toList());
    }

    @Override
    public boolean customerTransfer(CustomerTransferReq req) {
        // 参数判断
        if (CollectionUtil.isEmpty(req.getCustomerIdList()) || ObjectUtil.isNull(req.getUserId())) {
            throw new RRException(RRExceptionCodeEnum.PARAM_ERROR);
        }

        // 流转记录新增 获取客户原有数据
        List<CustomerDetailPo> detailPoList = customerService.customerPoDetailList(new CustomerDetailListDo().setIdList(req.getCustomerIdList()));
        if (CollectionUtil.isEmpty(detailPoList)) {
            return false;
        }

        // 获取被转让人信息
        EntUserInfo userInfo = userInfoService.getById(req.getUserId());
        if (ObjectUtil.isNull(userInfo)) {
            return false;
        }

        // 记录日志添加
        List<CustomerFlow> flowBatchDo = detailPoList.stream()
                .map(po -> {
                    CustomerFlow customerFlow = new CustomerFlow();
                    customerFlow.setCustomerId(po.getId())
                            .setActionTag(CustomerConst.FlowActionTag.FLOW_USER_CHANGE.getId())
                            .setOriginalUserId(po.getFollowUserId())
                            .setOriginalUserName(po.getFollowUserName())
                            .setTargetUserId(userInfo.getId())
                            .setRemark(req.getRemark())
                            .setTargetUserName(userInfo.getNickName())
                            .setCreateByName(ShiroUtils.getUserEntity().getNickName());
                    return customerFlow;
                }).collect(Collectors.toList());
        flowService.saveBatch(flowBatchDo);

        // 记录信息修改
        customerService.update(
                new LambdaUpdateWrapper<Customer>()
                        .in(Customer::getId, req.getCustomerIdList())
                        .set(Customer::getFollowUserId, req.getUserId()));

        List<Customer> customerList = detailPoList.stream().map(po -> {
            Customer customer = new Customer();
            BeanUtil.copyProperties(po, customer);
            return customer;
        }).collect(Collectors.toList());
        msgComponent.customerTransfer(customerList, userInfo, req.getRemark());
        return true;
    }

    @Override
    public boolean mainlyCancel(List<Long> idList) {
        return customerService.update(
                new LambdaUpdateWrapper<Customer>()
                        .in(Customer::getId, idList)
                        .set(Customer::getMainlyFlag, CommonConst.FlagEnum.NOT.getId()));
    }

    @Override
    public boolean mainly(List<Long> idList) {
        return customerService.update(
                new LambdaUpdateWrapper<Customer>()
                        .in(Customer::getId, idList)
                        .set(Customer::getMainlyFlag, CommonConst.FlagEnum.IS.getId()));
    }

    @Override
    public CustomerDetailRes customerDetail(Long id) {
        CustomerDetailPo customerDetailPo = customerService.customerPoDetail(new CustomerDetailDo().setId(id));
        if (ObjectUtil.isNull(customerDetailPo)) {
            throw new RRException(RRExceptionCodeEnum.PARAM_ERROR);
        }
        CustomerDetailRes res = new CustomerDetailRes();
        BeanUtil.copyProperties(customerDetailPo, res);

        // 避免客户信息 areaId 对应的 区域信息不存在，配合前端区域下拉展示 LLz 2021.12.3
        if (StrUtil.isBlank(res.getAreaName())) {
            res.setAreaId(null);
        }

        if (CommonConst.FlagEnum.IS.getId().equals(customerDetailPo.getEnterpriseFlag())) {
            // 获取资质图片
            res.setQualiImageList(
                    qualiImageService.list(
                                    new LambdaQueryWrapper<CustomerQualiImage>()
                                            .eq(CustomerQualiImage::getCustomerId, id))
                            .stream()
                            .map(CustomerQualiImage::getImageUrl)
                            .collect(Collectors.toList()));

            // 资质列表
            List<QualiConf> qualiConfList = customerService.qualiConfList(id);

            res.setQualiList(
                    qualiConfList.stream()
                            .map(qualiConf -> {
                                QualiMatchRes qualiRes = new QualiMatchRes();
                                BeanUtil.copyProperties(qualiConf, qualiRes);
                                qualiRes.setName(qualiConf.getQualiCode(), qualiConf.getGradeTag());
                                return qualiRes;
                            })
                            .collect(Collectors.toList()));
            res.setQualiListDetail(qualiListDetailEncap(qualiConfList));
        }

        if (CustomerConst.TypeEnum.DEAL.getId().equals(customerDetailPo.getTypeId())) {
            CustomerCooperationDo customerCooperationDo = new CustomerCooperationDo();
            customerCooperationDo.setCustomerIdList(Collections.singletonList(customerDetailPo.getId()));
            List<CustomerCooperationPo> cooperationCountList = cooperationService.countCooperation(customerCooperationDo);
            if (CollectionUtil.isNotEmpty(cooperationCountList)) {
                CustomerCooperationPo cooperationCount = CollectionUtil.getFirst(cooperationCountList);
                res.setIncomeCount(cooperationCount.getIncomeCount())
                        .setUnConsumeCount(cooperationCount.getIncomeCount().subtract(cooperationCount.getConsumeCount()));
            }
        }

        if (!CustomerConst.TypeEnum.GENERAL.getId().equals(customerDetailPo.getTypeId())) {

            // 判断当前用户是否是跟进人上级
            UserInfo userEntity = ShiroUtils.getUserEntity();
            List<Long> deptChildIdList
                    = deptInfoPlusService.deptList(new TenantDeptInfoPlusDo().setAncestorId(userEntity.getTenantDeptId()))
                    .stream().map(TenantDeptInfoPlusPo::getId)
                    .collect(Collectors.toList());
            List<Long> roleDataDeptIdList = roleDeptDataAssoService
                    .listPo(new RoleDeptDataDo().setUserId(userEntity.getDeptId()))
                    .stream().map(RoleDeptDataPo::getDeptId).collect(Collectors.toList());
            deptChildIdList.addAll(roleDataDeptIdList);

            List<EntUserEmployeeInfoListPo> followerInfoList
                    = userInfoService.userEmployeeInfoListPo(new EntUserEmployeeInfoListDo().setId(res.getFollowUserId()));
            EntUserEmployeeInfoListPo followerInfo = CollectionUtil.getFirst(followerInfoList);
            if (ObjectUtil.isNotNull(followerInfo) && UserInfoUtil.managerJudge(userEntity) && userEntity.getTenantDeptId().equals(followerInfo.getDeptId())) {
                res.setSubordinateFlag(CommonConst.FlagEnum.IS.getId());
            }
            if (ObjectUtil.isNotNull(followerInfo) && !userEntity.getTenantDeptId().equals(followerInfo.getDeptId())
                    && deptChildIdList.contains(followerInfo.getDeptId())) {
                res.setSubordinateFlag(CommonConst.FlagEnum.IS.getId());
            }
        }

        return res;
    }

    /**
     * 资质列表封装成资质信息
     * <p>
     * 资质进行排序，总包、专包、不分等级（分行显示）
     * </p>
     *
     * @param qualiConfList 资质信息列表
     * @return 资质信息
     */
    private String qualiListDetailEncap(List<QualiConf> qualiConfList) {
        List<QualiConf> nonQualiList = qualiConfList
                .stream()
                .filter(qualiConf -> QualiConst.GradeType.NULL.getTag().equals(qualiConf.getGradeTag()))
                .collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(nonQualiList)) {
            return QualiConst.GradeType.NULL.getType();
        }

        // 获取不分等级的
        String noGrade = qualiConfList
                .stream()
                .filter(quali -> QualiConst.GradeType.NO_GRADE.getTag().equals(quali.getGradeTag()))
                .map(qualiConf -> {
                    QualiMatchRes qualiRes = new QualiMatchRes();
                    BeanUtil.copyProperties(qualiConf, qualiRes);
                    qualiRes.setName(qualiConf.getQualiCode(), qualiConf.getGradeTag());
                    return qualiRes;
                })
                .map(QualiMatchRes::getName)
                .collect(Collectors.joining(","));

        // 总承包
        String EPCQualis = qualiConfList
                .stream()
                .filter(quali -> !QualiConst.GradeType.NO_GRADE.getTag().equals(quali.getGradeTag())
                        && QualiConst.TypeTag.EPC.getTag().equals(quali.getTypeTag()))
                .map(qualiConf -> {
                    QualiMatchRes qualiRes = new QualiMatchRes();
                    BeanUtil.copyProperties(qualiConf, qualiRes);
                    qualiRes.setName(qualiConf.getQualiCode(), qualiConf.getGradeTag());
                    return qualiRes;
                })
                .sorted(Comparator.comparing(QualiMatchRes::getGradeTag))
                .map(QualiMatchRes::getName)
                .collect(Collectors.joining(","));
        // 专业承包
        String professionQualis = qualiConfList
                .stream()
                .filter(quali -> !QualiConst.GradeType.NO_GRADE.getTag().equals(quali.getGradeTag())
                        && QualiConst.TypeTag.PROFESSIONAL_CONTRACTORS.getTag().equals(quali.getTypeTag()))
                .map(qualiConf -> {
                    QualiMatchRes qualiRes = new QualiMatchRes();
                    BeanUtil.copyProperties(qualiConf, qualiRes);
                    qualiRes.setName(qualiConf.getQualiCode(), qualiConf.getGradeTag());
                    return qualiRes;
                })
                .sorted(Comparator.comparing(QualiMatchRes::getGradeTag))
                .map(QualiMatchRes::getName)
                .collect(Collectors.joining(","));

        return (StringUtil.isNotBlank(EPCQualis) ? (QualiConst.TypeTag.EPC.getType() + "：" + EPCQualis) + "\n" : "")
                + (StringUtil.isNotBlank(professionQualis) ? (QualiConst.TypeTag.PROFESSIONAL_CONTRACTORS.getType() + "：" + professionQualis + "\n") : "")
                + (StringUtil.isNotBlank(noGrade) ? (QualiConst.GradeType.NO_GRADE.getType() + "：" + noGrade) : "");
    }

    /**
     * 分页排序规则封装
     *
     * @param pageDo 分页信息
     * @param req    分页请求参数
     */
    private void handlerPagingOrder(Page<Customer> pageDo, PageItemDTO<CustomerPagingReq> req) {
        // 处理排序功能：
        //if (StrUtil.isNotBlank(req.getOrderBy())) {
        List<OrderItem> orders = new ArrayList<>();
        if (StrUtil.isNotBlank(req.getOrderBy())) {
            String orderColumn = null;
            if ("name".equals(req.getOrderBy())) {
                orderColumn = "xc.name";
            }
            if ("transferDates".equals(req.getOrderBy())) {
                orders.add(OrderItem.asc("ISNULL(xcf_transfer_time.create_time)"));
                orderColumn = "xcf_transfer_time.create_time";
            }
            if ("cityId".equals(req.getOrderBy())) {
                orderColumn = "xc.city_id";
            }
            if ("areaId".equals(req.getOrderBy())) {
                orderColumn = "xc.area_id";
            }
            if ("contactsName".equals(req.getOrderBy())) {
                orderColumn = "xc.contacts_name";
            }
            if ("contactsPosition".equals(req.getOrderBy())) {
                orders.add(OrderItem.asc("ISNULL(xc.contacts_position)"));
                orderColumn = "xc.contacts_position";
            }
            if ("thisYearDealFlag".equals(req.getOrderBy())) {
                orderColumn = "xc.this_year_deal_flag";
            }
            if ("lastYearDealFlag".equals(req.getOrderBy())) {
                orderColumn = "xc.last_year_deal_flag";
            }
            if ("followUserName".equals(req.getOrderBy())) {
                orderColumn = "tui.nick_name";
            }
            if ("createTime".equals(req.getOrderBy())) {
                orderColumn = "xc.create_time";
            }
            if (StrUtil.isNotBlank(orderColumn)) {
                orders.add("asc".equals(req.getInOrder()) ? OrderItem.asc(orderColumn) : OrderItem.desc(orderColumn));
            }
        }
        // 默认的排序规则
        orders.add(OrderItem.asc("xc.city_id"));
        orders.add(OrderItem.asc("xc.area_id"));
        orders.add(OrderItem.asc("xc.follow_user_id"));
        orders.add(OrderItem.desc("xc.id"));
        pageDo.setOrders(orders);
    }

    @Override
    public PageItemVO<CustomerPagingRes> customerPaging(PageItemDTO<CustomerPagingReq> req) {
        Page<Customer> pageDo = new Page<>(req.getPageNum(), req.getPageSize());
        // 非区域名单的时候，销售只展示自己的客户
        CustomerPagingDo customerPagingDo = customerPagingFilter(req.getConditions());
        handlerPagingOrder(pageDo, req);
        //}
        /*if (StrUtil.isNotBlank(req.getOrderBy())) {
            PageOrderDo orderDo = new PageOrderDo();
            orderDo.setOrderBy(req.getOrderBy());
            if (StrUtil.isNotBlank(req.getInOrder()) && "asc".equals(req.getInOrder())) {
                orderDo.setInOrder(req.getInOrder());
            }
            customerPagingDo.setPageOrderDo(orderDo);
        }*/

        Page<CustomerPagingPo> pagingPo = customerService.customerPoPaging(pageDo, customerPagingDo);

        PageItemVO<CustomerPagingRes> pagingRes = PageItemUtil.toPageItemVO(pagingPo, new PageItemVO<>());

        // 获取区域信息
        Map<Long, String> areaMapById = areaService.list().stream().collect(Collectors.toMap(Area::getId, Area::getName));

        Map<Long, CustomerQualiPo> qualiPoMapByCustomerId = new HashMap<>();
        Map<Long, CustomerFollow> followMapByCustomerId = new HashMap<>();
        Map<Long, List<CustomerCooperation>> cooperationListGroupByCustomerId = new HashMap<>();
        Map<Long, List<EntAreaSalePo>> saleListGroupByAreaId = new HashMap<>();
        if (CollectionUtil.isNotEmpty(pagingPo.getRecords())) {
            // 获取客户列表id
            List<Long> customerIdList = pagingPo.getRecords()
                    .stream()
                    .map(CustomerPagingPo::getId)
                    .collect(Collectors.toList());

            if (CustomerConst.TypeEnum.GENERAL.getId().equals(customerPagingDo.getTypeId())) {
                // 获取对应资质信息
                qualiPoMapByCustomerId = customerService.customerQualiPoList(new CustomerQualiDo()
                                .setCustomerIdList(customerIdList))
                        .stream()
                        .collect(Collectors.toMap(CustomerQualiPo::getCustomerId, Function.identity()));

                List<Long> areaIdList = pagingPo.getRecords().stream()
                        .map(CustomerPagingPo::getAreaId).collect(Collectors.toList());
                saleListGroupByAreaId = areaSaleService.listPo(new EntAreaSaleDo().setAreaIdList(areaIdList))
                        .stream()
                        .collect(Collectors.groupingBy(EntAreaSalePo::getAreaId));
            }

            // 获取跟进数据
            followMapByCustomerId = followService.selectLastFollowList(customerIdList).stream()
                    .collect(Collectors.toMap(CustomerFollow::getCustomerId, Function.identity()));

            cooperationListGroupByCustomerId = cooperationService.list(new LambdaQueryWrapper<CustomerCooperation>()
                            .in(CustomerCooperation::getCustomerId, customerIdList)
                            .orderByDesc(CustomerCooperation::getIncomeDate))
                    .stream()
                    .collect(Collectors.groupingBy(CustomerCooperation::getCustomerId));
        }

        List<CustomerPagingRes> resList = new ArrayList<>();
        CustomerPagingRes res;
        String cityName;
        String areaName;
        List<CustomerCooperation> cooperationList;
        for (CustomerPagingPo po : pagingPo.getRecords()) {
            res = new CustomerPagingRes();
            BeanUtil.copyProperties(po, res);
            // 安许日期
            if (ObjectUtil.isNotNull(po.getSecurityLicenseExpiryDate())) {
                res.setSecurityLicenseExpiryDate(DateUtil.formatDate(po.getSecurityLicenseExpiryDate()));
            }
            // 区域信息
            cityName = areaMapById.get(po.getCityId());
            areaName = areaMapById.get(po.getAreaId());
            res.setCityName(StrUtil.isBlank(cityName) ? "" : cityName);
            res.setAreaName(StrUtil.isBlank(areaName) ? "" : areaName);

            if (qualiPoMapByCustomerId.containsKey(po.getId())) {
                res.setQualiNames(qualiPoMapByCustomerId.get(po.getId()).getQualiNames());
            }

            // 跟进记录
            if (followMapByCustomerId.containsKey(po.getId())) {
                CustomerFollow followInfo = followMapByCustomerId.get(po.getId());
                res.setLastFollow("(" + DateUtil.format(followInfo.getCreateTime(), DatePattern.NORM_DATETIME_MINUTE_PATTERN) + ")" + followInfo.getContent());
            }

            // 合作记录
            if (cooperationListGroupByCustomerId.containsKey(po.getId())) {
                cooperationList = cooperationListGroupByCustomerId.get(po.getId());
                res.setLastDealTime(DateUtil.format(CollectionUtil.getFirst(cooperationList).getIncomeDate(), DatePattern.NORM_DATE_PATTERN));
                res.setLastDealCost(CollectionUtil.getFirst(cooperationList).getIncome().toString());
                res.setTotalCost(cooperationList.stream().map(CustomerCooperation::getIncome).reduce(BigDecimal.ZERO, BigDecimal::add));
                res.setCostAmount(cooperationList.size());
            }

            // 区域销售名称
            if (saleListGroupByAreaId.containsKey(po.getAreaId())) {
                res.setSaleNames(
                        saleListGroupByAreaId.get(po.getAreaId())
                                .stream()
                                .map(EntAreaSalePo::getSaleName)
                                .collect(Collectors.joining("、")));
            }
            resList.add(res);
        }
        pagingRes.setRecords(resList);
        return pagingRes;
    }

    /**
     * 区域名单数据过滤条件封装
     *
     * @param conditions 条件
     * @return 条件信息
     */
    private CustomerPagingDo customerPagingFilter(CustomerPagingReq conditions) {

        CustomerPagingDo customerPagingDo = new CustomerPagingDo();
        BeanUtil.copyProperties(conditions, customerPagingDo);
        // 非区域名单的时候，销售只展示自己的客户
        /*
         * 客户数据过滤：
         *   一、区域名单
         *          1-管理人：看到管理区域下的名单数据
         *          2-销售：只能看到负责区域的客户
         *   二、成交客户
         *          1-管理人：
         *              看到自己的和角色数据授权部门下跟进人信息
         *              可以筛选跟进人信息
         *          2-销售：看到自己为跟进人的信息
         *  三、意向客户：
         *      只能看到自己得客户/管理下部门人信息
         * 所有数据需要和数据授权取并集
         * 需求修改 20220321 BY ZJ：
         *     1. 成交客户/意向客户:
         *      1. 超级管理员-》看到所有区域
         *      2. 管理层-》看到自己以及自己部门以下的人的数据
         *      3. 非管理层-》看到自己的数据
         *     2. 区域名单：
         *      1. 超级管理员-》看到所有区域信息
         *      2. 管理层-》看到自己部门中人员的负责区域
         *      3. 非管理层-》看到自己负责的区域信息
         */
        UserInfo userEntity = ShiroUtils.getUserEntity();
        if (!UserInfoUtil.entSuperAdminJudge(userEntity)) {

            // 获取当前用户数据授权部门id
            LambdaQueryWrapper<RoleDeptDataAsso> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.in(RoleDeptDataAsso::getRoleId, userEntity.getRoleIdList());
            List<Long> deptIdList = roleDeptDataAssoService.listPo(new RoleDeptDataDo().setUserId(userEntity.getId()))
                    .stream().map(RoleDeptDataPo::getDeptId).collect(Collectors.toList());

            // 区域名单
            if (CustomerConst.TypeEnum.GENERAL.getId().equals(conditions.getTypeId())) {

                // 获取 所授权部门下人员的销售区域
                List<Long> areaIdList = new ArrayList<>();
                if (CollectionUtil.isNotEmpty(deptIdList)) {
                    areaIdList = areaSaleService.listPo(new EntAreaSaleDo().setDeptIdList(deptIdList))
                            .stream().map(EntAreaSalePo::getAreaId).collect(Collectors.toList());
                }

                // 管理层条件筛选
                if (UserInfoUtil.managerJudge(userEntity)) {
                    // 获取当前用户部门下的子部门id列表
                    TenantDeptInfoPlusDo tenantDeptInfoPlusDo = new TenantDeptInfoPlusDo();
                    tenantDeptInfoPlusDo.setAncestorId(userEntity.getTenantDeptId());
                    List<Long> managerDeptIdList = deptInfoPlusService.deptList(tenantDeptInfoPlusDo)
                            .stream().map(TenantDeptInfoPlusPo::getId)
                            .collect(Collectors.toList());

                    // 获取对应部门的人员列表
                    List<Long> userList = userInfoService.userPoList(new UserDo().setDeptIdList(managerDeptIdList))
                            .stream()
                            .map(UserPo::getId)
                            .collect(Collectors.toList());
                    CustomerPagingDo.GeneralManagerInfo managerInfo = customerPagingDo.new GeneralManagerInfo(userEntity.getId(), userList, areaIdList);
                    customerPagingDo.setGeneralManagerInfo(managerInfo);
                } else {

                    // 对应区域下的信息
                    CustomerPagingDo.GeneralSale generalSale = customerPagingDo.new GeneralSale(userEntity.getId(), areaIdList);
                    customerPagingDo.setGeneralSale(generalSale);
                }
            }
            if (CustomerConst.TypeEnum.INTENTION.getId().equals(conditions.getTypeId())
                    || CustomerConst.TypeEnum.DEAL.getId().equals(conditions.getTypeId())) {
                if (UserInfoUtil.managerJudge(ShiroUtils.getUserEntity())) {

                    // 获取当前用户部门下的子部门id列表
                    TenantDeptInfoPlusDo tenantDeptInfoPlusDo = new TenantDeptInfoPlusDo();
                    tenantDeptInfoPlusDo.setAncestorId(userEntity.getTenantDeptId());
                    List<Long> managerDeptIdList = deptInfoPlusService.deptList(tenantDeptInfoPlusDo)
                            .stream().map(TenantDeptInfoPlusPo::getId)
                            .collect(Collectors.toList());
                    managerDeptIdList.addAll(deptIdList);
                    customerPagingDo.setManagerDeptIdList(managerDeptIdList);
                } else {
                    CustomerPagingDo.UnGeneralSale unGeneralSale = customerPagingDo.new UnGeneralSale(userEntity.getId(), deptIdList);
                    // customerPagingDo.setFollowUserId(ShiroUtils.getUserId());
                    customerPagingDo.setUnGeneralSale(unGeneralSale);
                }
            }
        }
        if (ObjectUtil.isNotNull(conditions.getDeptId())) {
            // 获取旗下部门id
            TenantDeptInfoPlusDo tenantDeptInfoPlusDo = new TenantDeptInfoPlusDo();
            tenantDeptInfoPlusDo.setAncestorId(conditions.getDeptId());
            List<Long> deptIdList = deptInfoPlusService.deptList(tenantDeptInfoPlusDo)
                    .stream().map(TenantDeptInfoPlusPo::getId)
                    .collect(Collectors.toList());
            customerPagingDo.setDeptIdList(deptIdList);
        }
        if (ObjectUtil.isNotNull(conditions.getAreaSaleDeptId())) {
            TenantDeptInfoPlusDo tenantDeptInfoPlusDo = new TenantDeptInfoPlusDo();
            tenantDeptInfoPlusDo.setAncestorId(conditions.getAreaSaleDeptId());
            List<Long> deptIdList = deptInfoPlusService.deptList(tenantDeptInfoPlusDo)
                    .stream().map(TenantDeptInfoPlusPo::getId)
                    .collect(Collectors.toList());
            List<Long> saleAreaIdList = areaSaleService.listPo(new EntAreaSaleDo().setDeptIdList(deptIdList))
                    .stream().map(EntAreaSalePo::getAreaId).collect(Collectors.toList());
            customerPagingDo.setSaleAreaIdList(saleAreaIdList);
        }
        return customerPagingDo;
    }

    @Override
    public boolean update(CustomerUpdateReq req) {
        if (ObjectUtil.isNull(req.getId())) {
            return false;
        }

        Customer customerPo = customerService.getById(req.getId());
        if (ObjectUtil.isNull(customerPo)
                || CommonConst.FlagEnum.IS.getId().equals(customerPo.getDelFlag())) {
            return false;
        }

        // 如果是企业客户，对客户的信用代码进行判断
        if (CommonConst.FlagEnum.IS.getId().equals(customerPo.getEnterpriseFlag()) && StrUtil.isNotBlank(req.getCertificateCode())) {
            List<Customer> customerList = customerService.list(new LambdaQueryWrapper<Customer>()
                    .ne(Customer::getId, req.getId())
                    .eq(Customer::getCertificateCode, req.getCertificateCode())
                    .eq(Customer::getDelFlag, CommonConst.FlagEnum.NOT.getId()));
            if (CollectionUtil.isNotEmpty(customerList)) {
                throw new RRException(RRExceptionCodeEnum.CUSTOMER_CODE_REPEAT);
            }
        }

        return CustomerMode.update(customerPo.getTypeId(), customerPo.getEnterpriseFlag(), req);
    }

    @Override
    public boolean delete(@Validated @NotEmpty List<Long> idList) {

        // 流转记录创建
        List<CustomerFlow> flowBatchDo = idList.stream()
                .map(customerId -> {
                    CustomerFlow customerFlow = new CustomerFlow();
                    customerFlow.setCustomerId(customerId)
                            .setActionTag(CustomerConst.FlowActionTag.DELETE.getId())
                            .setCreateByName(ShiroUtils.getUserEntity().getNickName());
                    return customerFlow;
                }).collect(Collectors.toList());

        // 创建删除流转记录
        flowService.saveBatch(flowBatchDo);

        List<Customer> customerList = customerService.list(new LambdaQueryWrapper<Customer>().in(Customer::getId, idList));

        // 删除
        boolean deleteResult = customerService.deleteByIdList(idList);

        if (!deleteResult) {
            return false;
        }
        msgComponent.customerDelete(customerList);
        return true;
    }

    @Override
    public boolean customerSave(CustomerSaveReq req) {
        // 如果是企业客户，对客户的信用代码进行判断
        if (CommonConst.FlagEnum.IS.getId().equals(req.getEnterpriseFlag()) && StrUtil.isNotBlank(req.getCertificateCode())) {
            List<Customer> customerList = customerService.list(new LambdaQueryWrapper<Customer>()
                    .eq(Customer::getCertificateCode, req.getCertificateCode())
                    .eq(Customer::getDelFlag, CommonConst.FlagEnum.NOT));
            if (CollectionUtil.isNotEmpty(customerList)) {
                throw new RRException(RRExceptionCodeEnum.CUSTOMER_CODE_REPEAT);
            }
        }
        // 如果是成交客户 需要添加成交记录
        if (CustomerConst.TypeEnum.DEAL.getId().equals(req.getTypeId())) {
            if (ObjectUtil.isNull(req.getCooperationInfo())) {
                throw new RRException(RRExceptionCodeEnum.CUSTOMER_DEAL_SAVE_NEED_COOPERATION_INFO);
            } else {
                CustomerCooperationSaveReq cooperationInfo = req.getCooperationInfo();
                // 必要字段判断
                if (StrUtil.isBlank(cooperationInfo.getIncomeAccount()) ||
                        ObjectUtil.isNull(cooperationInfo.getIncome()) || StrUtil.isBlank(cooperationInfo.getIncomeDate())
                        || ObjectUtil.isNull(cooperationInfo.getPerfor())
                        || CollectionUtil.isEmpty(cooperationInfo.getIncomeDetailList())) {
                    throw new RRException(RRExceptionCodeEnum.PARAM_ERROR);
                }
            }
        }
        // 资质id Null元素去除
        if (CollectionUtil.isNotEmpty(req.getQualiIdList())) {
            req.getQualiIdList().removeAll(Collections.singletonList(null));
        }
        return CustomerMode.save(req);
    }

    @Override
    public ExcelImportResultRes entBatchSave(CustomerBatchSaveReq req, String menuName) {

        ExcelImportResultRes res = new ExcelImportResultRes();

        int index = 1;

        // 社会信用代码
        List<String> repeatCodeList = customerService.repeatCodeList(req.getCustomerInfoList().stream().map(CustomerEntImportExcel::getCertificateCode).collect(Collectors.toList()));

        // 重复信用代码
        List<String> repeatExcelCodeList = repeatExcelCodeList(req.getCustomerInfoList());

        List<Area> areaList = CustomerConst.TypeEnum.GENERAL.getId().equals(req.getTypeId()) ? areaService.listManagerOrSale() : areaService.list();
        // 区域名称
        Map<String, List<Area>> areaGroupByName = areaList.stream().collect(Collectors.groupingBy(Area::getName));

        // 资质
        Map<String, QualiMatchRes> qualiMatchMap = qualiConfService.qualiMatchMap();

        // 准备保存列表
        List<Customer> customerBatchDo = new ArrayList<>();

        Customer customerDo;
        for (CustomerEntImportExcel customerInfo : req.getCustomerInfoList()) {

            customerDo = entImportExcelFilter(customerInfo, res, index++, req.getTypeId(), req.getEnterpriseFlag(), repeatExcelCodeList, repeatCodeList, areaGroupByName, qualiMatchMap);

            if (ObjectUtil.isNull(customerDo)) {
                continue;
            }

            if (CommonConst.FlagEnum.IS.getId().equals(customerDo.getThisYearDealFlag())
                    || CommonConst.FlagEnum.IS.getId().equals(customerDo.getLastYearDealFlag())
                    || CustomerConst.TypeEnum.DEAL.getId().equals(req.getTypeId())) {
                customerDo.setRegularFlag(CommonConst.FlagEnum.IS.getId());
            }

            customerBatchDo.add(customerDo);
        }
        res.setFailAmount(res.getResultInfoList().size())
                .setSuccessAmount(customerBatchDo.size());

        customerService.saveDoBatch(customerBatchDo);
        if (CustomerConst.TypeEnum.GENERAL.getId().equals(req.getTypeId())) {
            msgComponent.customerBatchSave(customerBatchDo, menuName);
        }
        return res;
    }

    @Override
    public ExcelImportResultRes personBatchSave(CustomerBatchSaveReq req, String menuName) {

        ExcelImportResultRes res = new ExcelImportResultRes();
        int index = 1;
        // 区域名称
        List<Area> areaList = areaService.list();
        // 区域名称
        Map<String, List<Area>> areaGroupByName = areaList.stream().collect(Collectors.groupingBy(Area::getName));

        // 客户名称
        List<String> nameList = req.getCustomerInfoList().stream().map(CustomerEntImportExcel::getName).collect(Collectors.toList());
        List<String> repeatNameList = customerService
                .list(new LambdaQueryWrapper<Customer>()
                        .in(Customer::getName, nameList)
                        .eq(Customer::getDelFlag, CommonConst.FlagEnum.NOT.getId()))
                .stream().map(Customer::getName).collect(Collectors.toList());

        // 准备保存列表
        List<Customer> customerBatchDo = new ArrayList<>();
        Customer customerDo;
        for (CustomerEntImportExcel customerInfo : req.getCustomerInfoList()) {
            customerDo = personImportExcelFilter(customerInfo, res, index++, req.getTypeId(), req.getEnterpriseFlag(), repeatNameList, areaGroupByName);
            if (ObjectUtil.isNull(customerDo)) {
                continue;
            }
            customerBatchDo.add(customerDo);
        }

        res.setFailAmount(res.getResultInfoList().size())
                .setSuccessAmount(customerBatchDo.size());

        customerService.saveDoBatch(customerBatchDo);
        return res;
    }
}
